package ar.uba.dc.sistemas.monitorRW;

/**
 * 
 * Esta implementacion da preferencia a los lectores. 
 * Un lector no puede comenzar a leer si hay un escritor esperando, en otro caso puede comenzar inmediatamente.
 * Un escritor no puede comenzar a escribir mientras haya algun lector esperando o si hay algun escritor escribiendo 
 * 
 * @author Hernan Berroja Albiz / German del Tuffo
 * @version 0.1
 */

public class ReadersPreferred implements MultipleReadersWritersMonitor {
    /**
     * cantidad de lectores leyendo
     */
    protected int cantLectoresLeyendo = 0;
    /**
     * cantidad total de lectores (leyendo o esperando para leer)
     */
    protected int cantidadLectoresTotal = 0;
    /**
     * cantidad de escritores escribiendo (puede ser 0 o 1)
     */
    protected int cantidadEscritoresEscribiendo = 0;
    /**
     * cantidad total de escritores escribiendo o esperando
     */
    protected int cantEscritoresTotal = 0;

    /**
     * Este metodo resetea la estructura del monitor.
     */
    public void reset() {
        cantLectoresLeyendo = 0;
        cantidadLectoresTotal = 0;
        cantidadEscritoresEscribiendo = 0;
        cantEscritoresTotal = 0;
    }

    /**
     * Called to begin reading the shared data structure.
     * Will wait for access if necessary.
     * <p/>
     * Pattern for use:
     * <p/>
     * <pre>
     * 	mon.startReading();
     * 	try {
     * 	   ... read ...
     * 	} finally {
     * 	   mon.stopReading();
     * 	}
     * </pre>
     *
     */
    public synchronized void comenzarLectura()
            throws InterruptedException {
        cantidadLectoresTotal++;
        while (cantidadEscritoresEscribiendo != 0) wait();
        cantLectoresLeyendo++;
    }

    /**
     * Este metodo se llama cuando el proceso termina de leer el objeto compartido. 
     */
    public synchronized void detenerLectura() {
        cantLectoresLeyendo--;
        cantidadLectoresTotal--;
        if (cantidadLectoresTotal == 0) notify();
    }

    /**
     * Called to begin writing the shared data structure.
     * Will wait for access if necessary.
     * <p/>
     * Pattern for use:
     * <p/>
     * <pre>
     * 	mon.startWriting();
     * 	try {
     * 	   ... write ...
     * 	} finally {
     * 	   mon.stopWriting();
     * 	}
     * </pre>
     *
     * @throws InterruptedException If interrupted while waiting
     *                              for access.
     */
    public synchronized void comenzarEscritura()
            throws InterruptedException {
        cantEscritoresTotal++;
        while (cantidadLectoresTotal + cantidadEscritoresEscribiendo != 0) wait();
        cantidadEscritoresEscribiendo = 1;
    }

    /**
     * Este metodo es llamado cuando el proceso termina de escribir el objeto compartido.
     */
    public synchronized void detenerEscritura() {
        cantidadEscritoresEscribiendo = 0;
        cantEscritoresTotal--;
        notifyAll();
    }

    /**
     * Informacion acerca del tipo de implementacion del monitor.
     *
     * @return "Readers-Preferred Monitor"
     */
    public String getMonitorInfo() {
        return "Readers-Preferred Monitor";
    }
}

